package com.ymy.thinking.in.spring.dependency.lookup;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * {@link HierarchicalBeanFactory} 层次性依赖查找 Bean 示例
 *
 * @author Ringo
 * @date 2021/8/31 16:50
 */
public class HierarchicalDependencyLookupDemo {

    public static void main(String[] args) {
        // 创建 IoC 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册为 Bean
        applicationContext.register(HierarchicalDependencyLookupDemo.class);

        // 1: 获取 HierarchicalBeanFactory
        // ConfigurableListableBeanFactory 继承了 HierarchicalBeanFactory
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();

        // 这里返回 null
        System.out.println("当前 BeanFactory 的 Parent BeanFactory：" +
                beanFactory.getParentBeanFactory());

        // 2. 设置 Parent BeanFactory
        HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
        beanFactory.setParentBeanFactory(parentBeanFactory);

        System.out.println("当前 BeanFactory 的 Parent BeanFactory：" +
                beanFactory.getParentBeanFactory());

        // 开启 Spring 应用上下文
        applicationContext.refresh();

        // 查看是否包含 hello 这个 Bean
        displayContainsLocalBean(beanFactory, "hello");            // false
        displayContainsLocalBean(parentBeanFactory, "hello");      // true

        displayContainsBean(beanFactory, "hello");                 //  true
        displayContainsBean(parentBeanFactory, "hello");           // true

        // 关闭 Spring 应用上下文
        applicationContext.close();
    }


    // 既查当前 BeanFactory 又查父级 BeanFactory
    private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.println(containsBean(beanFactory, beanName));
    }

    // 递归查询（我们自己写的 containsBean的实现）
    public static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        // 拿到父级的 IoC 容器
        BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
        // 父级 IoC 容器是 HierarchicalBeanFactory
        if (parentBeanFactory instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory parentHierarchicalBeanFactory = (HierarchicalBeanFactory) parentBeanFactory;
            if (containsBean(parentHierarchicalBeanFactory, beanName)) {
                return true;
            }
        }
        // 父级 IoC 容器不是 HierarchicalBeanFactory, 就只查询当前容器
        // containsLocalBean 只返回当前 IoC 容器中的 Bean
        // 不会去查询父级的 IoC 容器
        return beanFactory.containsLocalBean(beanName);
    }

    // 只查本地 BeanFactory
    private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.println(beanFactory.containsLocalBean(beanName));
    }

    /**
     * 创建父级 {@link BeanFactory}
     */
    private static HierarchicalBeanFactory createParentBeanFactory() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        String location = "classpath:META-INF/hierarchical-dependency-lookup-context.xml";
        reader.loadBeanDefinitions(location);
        return beanFactory;
    }

}
